//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;

namespace OpenLS.Core.Serialization
{
    internal class AlternateContent
    {
        internal const string xmlName = "AlternateContent";
    }

    internal class AlternateContent<T> : AlternateContent where T : IOfficeXmlSerializable, new()
    {
        private readonly List<Choice<IOfficeXmlSerializable>> _choices = new List<Choice<IOfficeXmlSerializable>>();
        private Fallback<T> _fallback;

        public T Item
        {
            get {
                foreach (var choice in _choices)
                {
                    if (choice.Requires == null && choice.Item is T)
                        return (T)choice.Item;
                }
                return _fallback.Item;
            }
        }

        public void Read(ReadContext context, Func<ReadContext, IOfficeXmlSerializable> action,  Func<ReadContext, T> fallbackAction)
        {
            string s = context.ReaderLocalName;
            string namespaceUri = context.NamespaceUri;
            using (ReadContext c = context.ReadFromAlternateContent(OfficeConstants.markupCompatibility +  "AlternateContent"))
            {
                while (c.ReaderLocalName == "Choice")
                {
                    var choice = new Choice<IOfficeXmlSerializable>();
                    choice.Read(c, action);
                    _choices.Add(choice);
                }
                if (c.ReaderLocalName == "Fallback")
                {
                    _fallback = new Fallback<T>();
                    _fallback.Read(c, fallbackAction);
                }
            }
        }

        public void ReadOptional(string name, ReadContext context)
        {
            Read(context, c =>
                              {
                                  if (c._reader.NamespaceURI == c.NamespaceUri && c.ReaderLocalName == name)
                                    return c.ReadOptionalElement<T>(name);
                                  return c.ReadElement<ExtensionElement>();
                              }
                              , c =>
                              {
                                  return c.ReadOptionalElement<T>(name);
                              });
        }
    }

    internal delegate T2 Func<T1, T2>(T1 t2);


    class AlternateContentInner<T>
    {

        public T Item  
        {
            get; protected set;
        }
    }
    internal class Fallback<T> : AlternateContentInner<T>
    {

        public void Read(ReadContext context, Func<ReadContext, T> action)
        {
            using (var c = context.Read("Fallback"))
            {
                c.PassAttributes();
                Item = action(c);
            }
        }
    }

    internal class Choice<T> : AlternateContentInner<T>
    {
        public void Read(ReadContext context, Func<ReadContext, T> action)
        {
            using (var c = context.Read("Choice"))
            {
                this.Requires = c.GetOptionalString("Requires");
                
                c.PassAttributes();
                Item = action(c);
            }
        }

        public string Requires { get; private set; }
    }
}